package thread5;

/**
 * Created with IntelliJ IDEA
 * Description:
 * User:34398
 * Date:2024-07-02
 * Time:8:49
 * <p>
 * <p>
 * <p>
 * 创建线程有五种方法
 * 1、继承Thread
 * 2、实现Runnable接口
 * 3、Thread的匿名内部类
 * 4、Runnable的匿名内部类
 * <p>
 * 5、类似于2方法，不过使用lambda表达式实现————————————推荐，都要掌握
 * * 注意:3、4都是赋值给Thread这个类型 而且都要调用start()
 * <p>
 * <p>
 * idDaemon()是否是后台进程
 * 如果一个线程可以阻止一个进程的执行，那么他就叫前台线程
 * <p>
 * 一个线程不能阻止一个进程的执行（虽然进程结束，这个线程也会被带走）——————叫后台线程，也叫守护线程
 * 一些后台线程的结束不会影响前台线程的运行，更不会影响进程的运行
 * <p>
 * <p>
 * 创建的线程默认都是前台线程，所有前台线程结束，才能结束
 * <p>
 * 前台线程后，后台线程除了决定进程是否退出，在其他方面没有任何影响
 * <p>
 * 线程之间是并发执行的
 * <p>
 * 后台进程和前台进程与线程是两个不同的概念
 * <p>
 * 进程至少有一个前台线程
 * <p>
 * 代码中new的Thread线程 和内核中实际的线程不一定是一样的
 * 可能会出现 代码中的thread存在，但是内核中实际的线程已经不存在了（但是不会说出现***线程实际在，但代码中没有）
 * <p>
 * 原因有2
 * 1、调用start之前，线程还没有创建
 * run运行完，内核的线程就结束了 Thread对象仍然存在
 * 所以需要isAlive()判断对应线程是否存在于实际内核中
 * <p>
 * 线程之间的调度顺序是不确定的！！！！！！！！！！！！！
 * 他们的概率不是均分的，会因为系统、代码运行环境的不同而有所差异
 * <p>
 * start和run的区别：
 * run是描述一个线程具体如何做，是线程的入口（回调函数）
 * <p>
 * start是调用系统函数（根据各种系统，调用API，然后创建 PCB，加入到链表中）
 * start创建好的线程在，单独执行run()
 * <p>
 * start一般执行的很快，因为形成轻量
 * <p>
 * 调用start不一定要在main线程调用（主线程） 任何线程都可以创建一个新的线程
 * <p>
 * 一个Thread对象只能调用一次start函数，多次调用会出现问题！！！！！！！！！！！！！！
 * 因为一个Thread对象，对应一个线程
 */

//用lambda表达式创建，推荐

/**
 *
 *
 * 创建线程有五种方法
 * 1、继承Thread
 * 2、实现Runnable接口
 * 3、Thread的匿名内部类
 * 4、Runnable的匿名内部类
 *
 * 5、类似于2方法，不过使用lambda表达式实现————————————推荐，都要掌握
 *      * 注意:3、4都是赋值给Thread这个类型 而且都要调用start()
 * */


/**
 *
 * idDaemon()是否是后台进程
 * 如果一个线程可以阻止一个进程的执行，那么他就叫前台线程
 *
 * 一个线程不能阻止一个进程的执行（虽然进程结束，这个线程也会被带走）——————叫后台线程，也叫守护线程
 * 一些后台线程的结束不会影响前台线程的运行，跟不会影响进程的运行
 *
 *
 * 创建的线程默认都是前台线程，所有前台线程结束，才能结束
 *
 * 前台线程后后台线程除了决定进程是否退出，在其他方面没有任何影响
 *
 * 线程之间是并发执行的
 *
 * 后台进程和前台进程与线程是两个不同的概念
 *
 * 进程至少有一个前台线程
 * */

/**
 * 代码中new的Thread线程 和内核中实际的线程不一定是一样的
 *可能会出现 代码中的thread存在，但是内核中实际的线程已经不存在了（但是不会说出现***线程实际在，但代码中没有）
 *
 * 原因有2
 * 1、调用start之前，线程还没有创建
 * run运行完，内核的线程就结束了 Thread对象仍然存在
 * 所以需要isAlive()判断对应线程是否存在于实际内核中
 * */

/**
 * 线程之间的调度顺序是不确定的！！！！！！！！！！！！！
 * 他们的概率不是均分的，会因为系统、代码运行环境的不同而有所差异
 * */


/**
 * start和run的区别：
 * run是描述一个线程具体如何做，是线程的入口（回调函数）
 *
 * start是调用系统函数（根据各种系统，调用API，然后创建 PCB，加入到链表中）
 * start创建好的线程在，单独执行run()
 *
 * start一般执行的很快，因为形成轻量
 *
 * 调用start不一定要在main线程调用（主线程） 任何线程都可以创建一个新的线程
 *
 * 一个Thread对象只能调用一次start函数，多次调用会出现问题！！！！！！！！！！！！！！
 * 因为一个Thread对象，对应一个线程
 * */

/**
 * JAVA中结束线程是比较“温柔”的 他会让这个线程的run方法执行完毕，线程自然就结束了
 * 因为害怕对数据的修改出现错误，希望是一个完整的过程，要不全改，要不都不改
 *
 * 实际final (effectively final) 意思是虽然变量没有被final修饰，但是变量也是不可修改的*/

public class demo5 {

    private static boolean isQuit;//相当于外部类

    public static void main(String[] args) throws InterruptedException {

        isQuit = true;
        /**Runnable是一个函数式接口*/
        Thread thread = new Thread(() -> {//lambda表达式，相当于直接可以写run方法内部的逻辑(Runnable只有一个抽象方法，所以直接用lambda表达式)
            while (isQuit) {
                System.out.println("新的线程在执行");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        //lambda表达式是一个函数式接口 创建一个内部类 而内部类访问外部类成员是JAVA本来就允许的，所以不会有变量捕获 ，可以用isQuit来开关线程
        //lambda表达式只能捕获lambda表达式所在方法的局部变量？

        thread.start();
        isQuit = false;

        while (true) {
            System.out.println("主线程在执行");
            Thread.sleep(1000);
        }

    }
}
